import { Badge, Box, HorizontalStack, Link, Text } from "@shopify/polaris"
import func from "@/util/func"
import ShowListInBadge from "@/apps/dashboard/components/shared/ShowListInBadge"
import { operatorTypeOptions } from "@/apps/dashboard/pages/observe/api_collections/component/AdvancedSettingsComponent"

const reportTransform = {
    createVulnerableAPIsSeverity: (vulnerableTestingRunResults) => {
        const countMap = {
            CRITICAL: 0,
            HIGH: 0,
            MEDIUM: 0,
            LOW: 0,
        }

        vulnerableTestingRunResults.forEach(item => {
            const confidence = item.testResults.filter((result) => {
              return result.vulnerable
            }).map((result) => result.confidence)[0]
            countMap[confidence]++
        })

        const result = {
            "Critical": {
                "text": countMap.CRITICAL || 0,
                "color": func.getHexColorForSeverity("CRITICAL"),
                "filterKey": "Critical"
            },
            "High": {
                "text": countMap.HIGH || 0,
                "color": func.getHexColorForSeverity("HIGH"),
                "filterKey": "High"
            },
            "Medium": {
                "text": countMap.MEDIUM || 0,
                "color": func.getHexColorForSeverity("MEDIUM"),
                "filterKey": "Medium"
            },
            "Low": {
                "text": countMap.LOW || 0,
                "color": func.getHexColorForSeverity("LOW"),
                "filterKey": "Low"
            }
        }
        return result
    },
    getTotalUniqueApis: (vulnerableTestingRunResults) => {
        const uniqueApis = new Set()
        vulnerableTestingRunResults.forEach(item => {
            const endpointKey = `${item.apiInfoKey.apiCollectionId}-${item.apiInfoKey.method}-${item.apiInfoKey.url}`
            uniqueApis.add(endpointKey)
        })

        return uniqueApis.size
    },
    createVulnerabilityMap: (testingRunResults, categoryMap, subCategoryMap) => {
        let result = {}
        let categoryVsIssuesMap = {}
        let categoryVsApisCountMap = {}
        let categoryVsSeverityMap = {}
        let issueVsVulMap = {}
        let hostNameVsSeverityMap = {}
        let aktoFindingsTableData = []
        let aktoRecommendationsData = []
        let high = 0
        let medium = 0
        let low = 0
        let totalIssuesCount = 0

        const aktoSeverities = func.getAktoSeverities()

        testingRunResults?.length > 0 && testingRunResults.forEach((testingRun) => {
            let testSubtype = testingRun?.testSubType
            let testInfo = subCategoryMap?.[testSubtype]

            if (!testInfo) {
                return
            }
            let severity = testInfo?.superCategory?.severity?._name
            let severityIndex = 0;
            switch (severity) {
                case 'HIGH':
                    ++high
                    severityIndex = 2
                    break;
                case 'MEDIUM':
                    ++medium
                    severityIndex = 1
                    break;
                case 'LOW':
                    ++low
                    severityIndex = 0
                    break;
                default:
                    break;
            }

            let vulnerabilities = issueVsVulMap[testSubtype]
            if (vulnerabilities === undefined) {
                vulnerabilities = JSON.parse(JSON.stringify(testInfo))
            }
            let vulnerableTestingRunResults = vulnerabilities["vulnerableTestingRunResults"]
            if (vulnerableTestingRunResults === undefined) {
                vulnerableTestingRunResults = []
            }
            vulnerableTestingRunResults.push(testingRun)
            vulnerabilities['vulnerableTestingRunResults'] = vulnerableTestingRunResults
            vulnerabilities['severityIndex'] = severityIndex
            issueVsVulMap[testSubtype] = vulnerabilities
        })
        result = {
            ...result,
            severitiesCount: { HIGH: high, MEDIUM: medium, LOW: low }
        }
        let severityMapForIssueCategory = {}
        for (const [testSubType, issue] of Object.entries(issueVsVulMap)) {
            const categoryName = issue.superCategory.name
            const severity = issue?.superCategory?.severity?._name

            if (!categoryName) {
                continue
            }

            let issuesList
            if (!categoryVsIssuesMap.hasOwnProperty(categoryName)) {
                issuesList = []
                categoryVsIssuesMap[categoryName] = issuesList
            } else {
                issuesList = categoryVsIssuesMap[categoryName]
            }

            issuesList.push(issue)

            let apisCount = 0
            if (!categoryVsApisCountMap.hasOwnProperty(categoryName)) {
                categoryVsApisCountMap[categoryName] = 0
            } else {
                apisCount = categoryVsApisCountMap[categoryName]
            }

            if(severityMapForIssueCategory.hasOwnProperty(categoryName)){
                let initialCount = severityMapForIssueCategory[categoryName][severity] || 0
                severityMapForIssueCategory[categoryName][severity] = initialCount + issue?.vulnerableTestingRunResults?.length 
            }else{
                severityMapForIssueCategory[categoryName] = {}
                severityMapForIssueCategory[categoryName][severity] = issue?.vulnerableTestingRunResults?.length 
            }

            apisCount += issue.vulnerableTestingRunResults.length
            categoryVsApisCountMap[categoryName] = apisCount

            //Add to akto recommendation
            if (issue.hasOwnProperty("remediation")) {
                aktoRecommendationsData.push({
                    title: issue.testName,
                    content:  issue.remediation
                })
            }
        }

        // populate category vs severity map
        for (const [categoryName, issues] of Object.entries(categoryVsIssuesMap)) {

            // Initialize severity map for the category
            if (!categoryVsSeverityMap.hasOwnProperty(categoryName)) {
                categoryVsSeverityMap[categoryName] = func.getAktoSeveritiesInitMap()
            }

            for (const issue of issues) {
                const vulnerableTestingRunResults = issue?.vulnerableTestingRunResults
                
                if (!vulnerableTestingRunResults) continue
                
                for (const testingRun of vulnerableTestingRunResults) {
                    const testResults = testingRun?.testResults

                    if (!testResults || testResults.length === 0) {
                        continue
                    }

                    const severity = func.getRunResultSeverity(testingRun, subCategoryMap)

                    // Update the severity count for the category
                    if (aktoSeverities.includes(severity)) {
                        if (categoryVsSeverityMap[categoryName].hasOwnProperty(severity)) {
                            categoryVsSeverityMap[categoryName][severity] += 1
                        }
                    }

                    const vulnerableResultSampleData = reportTransform.getExtractedVulnerableResultSampleData(testResults)
                    const vulnerableResultMessage = reportTransform.getParsedSampleDataMessage(vulnerableResultSampleData)
                    const vulnerableResultReqUrl = vulnerableResultMessage?.request?.url || ''

                    let vulnerableResultReqHostName = ""

                    try {
                        const parsedURL = new URL(vulnerableResultReqUrl)
                        vulnerableResultReqHostName = parsedURL.hostname
                    } catch (error) {
                        continue
                    }

                    if (vulnerableResultReqHostName !== "") {
                        const aktoSeverities = func.getAktoSeverities()
                        if (aktoSeverities.includes(severity)) {
                            // Create severity map for the host if it doesn't exist
                            if (!hostNameVsSeverityMap.hasOwnProperty(vulnerableResultReqHostName)) {
                                const severitiesMap = aktoSeverities.reduce((acc, curr) => {
                                    acc[curr] = 0
                                    return acc
                                }, {})
                                hostNameVsSeverityMap[vulnerableResultReqHostName] = severitiesMap
                            }

                            // Increment the severity count for the host
                            hostNameVsSeverityMap[vulnerableResultReqHostName][severity] += 1
                        }
                    }
                }
            }
        }

        let totalTemplates = 0

        let issueSno = 1
        const severityLevels = func.getAktoSeverities().reverse()
        Object.keys(categoryVsIssuesMap).forEach((categoryName, index) => {
            const issuesArr = categoryVsIssuesMap[categoryName]
            totalTemplates += issuesArr.length
            issuesArr.forEach((issue, issueIndex) => {
                const severity = func.getRunResultSeverity(issue.vulnerableTestingRunResults[0], subCategoryMap)
                const severityIndex = severityLevels.indexOf(severity)
                totalIssuesCount += issue.vulnerableTestingRunResults.length
                aktoFindingsTableData.push({
                    key: issueSno,
                    sno: issueSno++,
                    issueNameComp: <Box><Link onClick={(e) => e.stopPropagation()} url={`#${issue.testName}`} removeUnderline><p style={{whiteSpace: 'normal'}}>{issue.testName}</p></Link></Box>,
                    issueName: issue.testName,
                    issueDescriptionComp: <Box><p style={{whiteSpace: 'normal'}}>{(issue.issueDescription.replace(/^"|"$/g, ''))}</p></Box>,
                    issueDescription: issue.issueDescription,
                    apisAffected: issue.vulnerableTestingRunResults.length,
                    issueCategory: issue.superCategory.displayName,
                    issueCategoryComp: <Box><p style={{whiteSpace: 'normal'}}>{issue.superCategory.displayName}</p></Box>,
                    issueImpactComp: <div className={`badge-wrapper-${severity}`}>
                                        <Badge size="small" key={issueIndex+'impact'}>{func.toSentenceCase(severity)}</Badge>
                                    </div>,
                    issueImpact: severityIndex,
                })
            })
        })

        const AKTO_RECOMMENDATIONS_LIMIT = 10
        if (aktoRecommendationsData.length > AKTO_RECOMMENDATIONS_LIMIT) {
            aktoRecommendationsData = aktoRecommendationsData.slice(0, AKTO_RECOMMENDATIONS_LIMIT)
        }

        aktoFindingsTableData.sort((a, b) => b.issueImpact - a.issueImpact)
        aktoFindingsTableData.forEach((item, index) => {
            item.sno = index + 1
        })

        result = {
            ...result,
            totalApisTested: reportTransform.getTotalUniqueApis(testingRunResults) || 0,
            totalIssues: totalIssuesCount || 0,
            categoryMap: categoryMap,
            categoryVsIssuesMap: categoryVsIssuesMap,
            categoryVsApisCountMap: categoryVsApisCountMap,
            categoryVsSeverityMap: categoryVsSeverityMap,
            aktoFindingsTableData: aktoFindingsTableData,
            aktoRecommendations: aktoRecommendationsData,
            topCategoriesChartData: reportTransform.prepareTopCategoriesChartData(categoryMap, categoryVsSeverityMap),
            hostNameVsSeverityMap: hostNameVsSeverityMap
        }

        return result
    },
    prepareReportTestConfigurationData: (testingRun, testingRunType, testRole, testingRunResultSummary, uniqueHostsTested, subCategoryMap) => {
        const initialReportTestConfigurationData = { general: [], testRole: [], advanced: [] }
        const reportTestConfigurationData = testingRun ? initialReportTestConfigurationData : {}

        const buildConfigurationSection = (section, dependency, buildSectionItem) => {
            if (section !== null && section !== undefined && dependency !== null && dependency !== undefined) {
                let item = buildSectionItem(dependency);
                if(item?.description !== undefined && item?.description.length !== 0){
                    section.push(item);
                }
            }
        };

        // ------- General Configuration
        const general = reportTestConfigurationData.general

        if (general) {
            buildConfigurationSection(general, testingRunType, (testingRunType) => ({
                id: "test-type",
                heading: "Test type",
                description: func.getRunTypeLabel(testingRunType, testingRun?.periodInSeconds),
            }));

            buildConfigurationSection(general, uniqueHostsTested, (uniqueHostsTested) => ({
                id: "unique-hosts-tested",
                heading: "Unique hosts tested",
                description: uniqueHostsTested,
            }));

            buildConfigurationSection(general, testingRun?.maxConcurrentRequests, (maxConcurrentRequests) => ({
                id: "max-concurrent-requests",
                heading: "Max concurrent requests",
                description: maxConcurrentRequests === -1 ? "Default" : maxConcurrentRequests,
            }));

            buildConfigurationSection(general, testingRun?.testingRunConfig?.overriddenTestAppUrl, (overriddenTestAppUrl) => ({
                id: "overridden-test-app-url",
                heading: "Overridden test app URL",
                description: overriddenTestAppUrl,
            }));

            buildConfigurationSection(general, testingRunResultSummary?.startTimestamp, (startTimestamp) => ({
                id: "test-start-time",
                heading: "Test started at",
                description: `${func.epochToDateTime(startTimestamp)}`,
            }));

            buildConfigurationSection(general, testingRunResultSummary?.endTimestamp, (endTimestamp) => ({
                id: "test-end-time",
                heading: "Test completed at",
                description: `${func.epochToDateTime(endTimestamp)}`,
            }));

            // Add Test categories section - categories for which test was run
            if (testingRun?.testingRunConfig?.testSubCategoryList && testingRun.testingRunConfig.testSubCategoryList.length > 0) {
                const testSubCategories = testingRun.testingRunConfig.testSubCategoryList;
                
                // Convert subcategory names to category display names
                const categoryNames = new Set(); // Use Set to avoid duplicates
                testSubCategories.forEach(subCategoryName => {
                    const subCategory = subCategoryMap?.[subCategoryName];
                    
                    if (subCategory?.superCategory?.displayName) {
                        categoryNames.add(subCategory.superCategory.displayName);
                    } else if (subCategory?.superCategory?.name) {
                        categoryNames.add(subCategory.superCategory.name);
                    }
                });
                
                const uniqueCategoryNames = Array.from(categoryNames).sort(); // Sort alphabetically
                
                if (uniqueCategoryNames.length > 0) {
                    buildConfigurationSection(general, uniqueCategoryNames, (categoryNames) => ({
                        id: "test-categories",
                        heading: "Test categories",
                        description: categoryNames.join(", "),
                    }));
                }
            }
        }

        // ------- Test Role Configuration
        const testRoleData = reportTestConfigurationData.testRole

        if (testRoleData) {
            buildConfigurationSection(testRoleData, testRole?.name, (name) => ({
                id: "test-role-name",
                heading: "Name",
                description: name,
            }));

            const authWithCondList = testRole?.authWithCondList
            if (authWithCondList && authWithCondList.length > 0) {
                authWithCondList.forEach((authWithCond, index) => {
                    buildConfigurationSection(testRoleData, authWithCond, (authWithCond) => {
                        const formattedAuthWithCondList = []

                        const authMechanismType = authWithCond.authMechanism?.type
                        formattedAuthWithCondList.push(`Type: ${authMechanismType}`)

                        const headerKVPairs = authWithCond.headerKVPairs
                        if (headerKVPairs && Object.keys(headerKVPairs).length > 0) {
                            const headerKey = Object.keys(headerKVPairs)[0]
                            const headerValue = headerKVPairs[headerKey]
                            formattedAuthWithCondList.push(`API header conditions: ${headerKey}=${headerValue}`)
                        }
                        return {
                            id: `auth-mechanism-${index + 1}`,
                            heading: `Auth mechanism - ${index + 1}`,
                            component: (
                                <ShowListInBadge
                                    itemsArr={formattedAuthWithCondList}
                                    status={"info"}
                                    useTooltip={true}
                                    wrap={true}
                                />
                            ),
                        }
                    })
                })
            }
        }

        // ------- Advanced Configuration
        const advanced = reportTestConfigurationData.advanced

        if (advanced) {
            const configsAdvancedSettings = testingRun?.testingRunConfig?.configsAdvancedSettings
            if (configsAdvancedSettings && configsAdvancedSettings.length > 0) {
                configsAdvancedSettings.forEach((advancedSetting) => {
                    buildConfigurationSection(advanced, advancedSetting, (advancedSetting) => {
                        const formattedOperationsGroupList = advancedSetting.operationsGroupList.map(operation => {
                            return operation.value.length > 0 ? `${operation.key}=${operation.value}` : `${operation.key}`
                        });

                        const operatorTypeOption = operatorTypeOptions[advancedSetting.operatorType] || {}

                        return {
                            id: advancedSetting.operatorType,
                            heading: operatorTypeOption?.heading,
                            component: (
                                <ShowListInBadge
                                    itemsArr={formattedOperationsGroupList}
                                    status={operatorTypeOption?.status}
                                    useTooltip={true}
                                    wrap={true}
                                />
                            ),
                        };
                    });
                })
            }
        }

        return reportTestConfigurationData
    },
    getExtractedVulnerableResultSampleData: (testResults) => {
        const vulnerableResult = [...(testResults || [])].reverse().find(result => result.vulnerable)
        let extractedData = {}

        if (vulnerableResult) {
            if (vulnerableResult.nodeResultMap) {
                let message= ''
                if(vulnerableResult?.executionOrder && vulnerableResult?.executionOrder.length > 0){
                    vulnerableResult.executionOrder.reverse().forEach(x => {
                        if(message.length === 0 && Object.keys(vulnerableResult.nodeResultMap[x]).length > 0){
                            message = vulnerableResult.nodeResultMap[x].message
                        }
                    });
                }
                extractedData = {
                    originalMessage: message,
                    message: message,
                    highlightPaths: []
                }
            } else {
                extractedData = {
                    originalMessage: vulnerableResult.message || '',
                    message: vulnerableResult.message || '',
                    highlightPaths: []
                }
            }
        }
        
        return extractedData
    },
    getParsedSampleDataMessage: (sampleData) => {
        let parsedSampleDataMessage = {}

        if (sampleData?.message) {
            try {
                const tmp = JSON.parse(sampleData.message);
                if(Array.isArray(tmp)){
                    parsedSampleDataMessage = tmp[0]
                }else{
                    parsedSampleDataMessage = tmp
                }
            } catch(err) {
                parsedSampleDataMessage = { "request": {}, "response": {} }
            }
        } 

        return parsedSampleDataMessage
    },
    prepareReportTestingTargetsData: (hostNameVsSeverityMap) => {
        let reportTestConfigurationData = []

        if (hostNameVsSeverityMap && Object.keys(hostNameVsSeverityMap).length > 0) {
            reportTestConfigurationData = Object.entries(hostNameVsSeverityMap).map(([hostName, hostVulnerabilitySeverities]) => {

                return {
                    id: hostName,
                    heading: hostName,
                    component: (
                        <HorizontalStack gap={"1"} wrap={true}>
                            {Object.entries(hostVulnerabilitySeverities).map(([severity, count]) => {
                                return count > 0 ? (
                                    <div className={`badge-wrapper-${severity}`} key={`${hostName}-${severity}`}>
                                        <Badge size="medium">
                                            <Text variant="bodySm">{`${func.toSentenceCase(severity)}: ${count}`}</Text>
                                        </Badge>
                                    </div>
                                ) : null;
                            })}
                        </HorizontalStack>
                    ),
                }
            });
        }

        return reportTestConfigurationData
    },
    prepareTopCategoriesChartData: (categoryMap, categoryVsSeverityMap) => {
        const LIMIT = 5
        const aktoSeverities = func.getAktoSeverities()
        const severitiesVsSeriesArrMap = func.getAktoSeveritiesInitMap(true) // Initialize with empty arrays for each severity

        const topCategories = Object.keys(categoryVsSeverityMap)
            .map(categoryName => ({
                categoryName,
                categoryDisplayName: categoryMap[categoryName]?.displayName || categoryName,
                totalSeverityCount: Object.values(categoryVsSeverityMap[categoryName]).reduce((acc, count) => acc + count, 0)
            }))
            .sort((a, b) => b.totalSeverityCount - a.totalSeverityCount)
            .slice(0, LIMIT)


        for (const category of topCategories) {
            const { categoryName, categoryDisplayName } = category
            
            for (const severity of aktoSeverities) {
                const seriesArr = severitiesVsSeriesArrMap[severity]
                const severityCount = categoryVsSeverityMap[categoryName][severity]

                seriesArr.push([categoryDisplayName, severityCount])
            }
        }

        const series = aktoSeverities.map(severity => {
            return {
                name: func.toSentenceCase(severity),
                data: severitiesVsSeriesArrMap[severity],
                color: func.getHexColorForSeverity(severity),
            }
        })

        const topCategoriesChartData = {
            defaultChartOptions: {
                "legend": {
                    enabled: false
                },
            },
            xAxis: {
                categories: topCategories.map(category => category.categoryDisplayName),
                title: {
                    text: 'Categories',
                },
                visible: true,
                gridLineWidth: 0,
            },
            series: series,
        }

        return topCategoriesChartData
    }
}

export default reportTransform